#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <ncurses.h>
#include <menu.h>

#define  const_nMaxCell 16
#if 1
int const_nMaxColumn()
{
	return (const_nMaxCell*3-2);
}
#endif
#define const_nMaxLine 16

#define defnLineBgn 3
#define defnColBgn 7


typedef struct 
{
	unsigned char data_cell[const_nMaxLine][const_nMaxCell][3];
}struct_cell_data;

typedef struct 
{
	unsigned char key[20];
	unsigned char menu[10];

}struct_main_menu;


static int main_menu(int menu_num);
static void prtwcell(int nline,int ncol,char* strpara,bool blReverse);
static bool getcellyx(WINDOW* win, int* nline, int* ncol, int* npos);

static bool editcellyx(WINDOW* win, int ch, struct_cell_data* type_cell_data);

static bool selectcellyx(WINDOW* win, int ch, struct_cell_data* type_cell_data);
static bool valid_first_cellyx(WINDOW* win, struct_cell_data* type_cell_data);


static bool goto_first_cellyx(WINDOW* win, struct_cell_data* type_cell_data)
{

	int nline=0,ncol=0;
	//int npos;

	//if(false==getcellyx(win, &nline, &ncol, &npos))
	//	return false;

	prtwcell(nline, ncol,(char*)&type_cell_data->data_cell[nline][ncol],true);


	return true;

}


static bool selectcellyx(WINDOW* win, int ch, struct_cell_data* type_cell_data)
{
#if 1
	int nline,ncol;
	int npos;

	if(false==getcellyx(win, &nline, &ncol, &npos))
		return false;

	prtwcell(nline, ncol,(char*)&type_cell_data->data_cell[nline][ncol],false);


	switch(ch)
	{
		case KEY_LEFT:
		{
			ncol--;
			if(ncol<0)
				ncol=0;
			break;
		}

		case KEY_RIGHT:
		{
			ncol++;
			if(ncol>=const_nMaxCell)
				ncol=const_nMaxCell-1;
			break;
		}

		case KEY_UP:
		{
			nline--;
			if(nline<0)
				nline=0;
			break;
		}

		case KEY_DOWN:
		{
			nline++;
			if(nline>=const_nMaxLine)
				nline=const_nMaxLine-1;

			break;
		}

	}
#endif

	prtwcell(nline, ncol,(char*)&type_cell_data->data_cell[nline][ncol],true);

	return true;

}


//unsigned char data_cell[const_nMaxLine][const_nMaxCell][3];

bool editcellyx(WINDOW* win, int ch, struct_cell_data* type_cell_data)
{
	int x,y;
	int nline,ncol;
	int npos;

	if(false==getcellyx(win, &nline, &ncol, &npos))
		return false;

	//if(x<defnColBgn+const_nMaxColumn()+1)
	{
		attron(A_REVERSE);
		type_cell_data->data_cell[nline][ncol][npos]=ch;
		printw("%c", type_cell_data->data_cell[nline][ncol][npos]);
		attroff(A_REVERSE);
		if(npos==1)
			move(nline+defnLineBgn, defnColBgn+ncol*3);
	}
	return true;

}

bool getcellyx(WINDOW* win, int* nline, int* ncol, int* npos)
{
	int x, y;
	getyx(win, y, x);

	if(x<defnColBgn)
		return false;
	if(x>defnColBgn+const_nMaxColumn()+1)
		return false;

	if(y<defnLineBgn)
		return false;
	if(y>=defnLineBgn+const_nMaxLine)
		return false;

	*nline=y-defnLineBgn;
	*ncol=(x-defnColBgn)/3;
	*npos=(x-defnColBgn)%3;

	return true;
}

void prtwcell(int nline,int ncol,char* strpara,bool blReverse)
{
	char str[25];
			//itoa(i, str, 16);
	str[0]=strpara[0];
	str[1]=strpara[1];
	str[2]=0;

	//sprintf(str,"%s",data_cell[nline][ncol]);
	move(nline+defnLineBgn,ncol*3+defnColBgn);
	if(blReverse)
		attron(A_REVERSE);
	else attroff(A_REVERSE);
	printw(str);
	move(nline+defnLineBgn,ncol*3+defnColBgn);
}

int main()
{	int ch;

	initscr();			/* Start curses mode 		*/
	raw();				/* Line buffering disabled	*/
	keypad(stdscr, TRUE);		/* We get F1, F2 etc..		*/
	noecho();			/* Don't echo() while we do getch */

    //printw("Type any character to see it in bold\n");
	int y, x;
    int nline, ncol;

	struct_cell_data type_cell_data;

    for(nline=0;nline<const_nMaxLine;nline++)
    {
    	for(ncol=0;ncol<const_nMaxCell;ncol++)
		{
			char str[25];
			//itoa(i, str, 16);
			sprintf(str,"%02X",nline*const_nMaxCell+ncol);
			memcpy(type_cell_data.data_cell[nline][ncol],str,2);
		}
	}
    
    for(nline=0;nline<const_nMaxLine;nline++)
    {
    	for(ncol=0;ncol<const_nMaxCell;ncol++)
		{
	    	prtwcell(nline, ncol,(char*)&type_cell_data.data_cell[nline][ncol],false);
		}
	}

	const struct_main_menu type_main_menu[]=
	{
		{
			"F1", "EC_REGA",
		},
		{
			"F2", "EC_REGB",
		},
		{
			"F3", "EC_RAM",
		},
		{
			"F4", "EC_DLM",
		},
		{
			"F5", "PNPCFG",
		},

		{
			"F6", "Other",
		},
		{
			"F7", "Quit",
		}

	};


	const struct_main_menu type_F1_menu[]=
	{ 
		{ "SMFI",        "0x1000",	},
		{ "INTC",        "0x1100",	},
		{ "E2CI",        "0x1200",	},
		{ "KBC",         "0x1300",	},
		{ "SWUC",        "0x1400",	},
		{ "PMC",         "0x1500",	},
		{ "GPIO",        "0x1600",	},
		{ "PS/2",        "0x1700",	},
		{ "PWM",         "0x1800",	},
		{ "ADC",         "0x1900",	},
		{ "DAC",         "0x1A00",	},
		{ "WUC",         "0x1B00",	},
		{ "SMBus",       "0x1C00",	},
		{ "KB Scan",     "0x1D00",	},
		{ "ECPM",        "0x1E00",	},
		{ "ETWD",        "0x1F00",	},
	};

	const struct_main_menu type_F2_menu[]=
	{ 
		{ "GCTRL",        "0x2000",	},
		{ "EGPC",         "0x2100",	},
		{ "BattRAM",      "0x2200",	},
		{ "CIR",          "0x2300",	},
		{ "TMKBC",        "0x2400",	},
		{ "DBGR",         "0x2500",	},
		{ "SSPI",         "0x2600",	},
		{ "UART0",        "0x2700",	},
		{ "UART1",        "0x2800",	},
		{ "TMR",          "0x2900",	},
		{ "HWM(SIO)",     "0x2A00",	},
		{ "GPIO(SIO)",    "0x2B00",	},
		{ "E-Flash",      "0x2C00",	},
		{ "CEC",          "0x2D00",	},
		{ "USBSW",        "0x2E00",	},
		{ "PECI",         "0x2F00",	},
		{ "ESPI0",        "0x3000",	},
		{ "ESPI1",        "0x3100",	},
		{ "ESPI2",        "0x3200",	},
		{ "ESPI3",        "0x3300",	},
		{ "SMB1",         "0x3400",	},
		{ "SMB2",         "0x3500",	},
		{ "USBPD0",       "0x3600",	},
		{ "USBPD1",       "0x3700",	},
		{ "ESPI0",        "0x3800",	},
		{ "LED DOTMTX",   "0x3900",	},
		{ "LED STRIP",    "0x3A00",	},


	};

	const struct_main_menu type_F3_menu[]=
	{ 
		{ "uC SFR",       "0x8000",	},
		{ "uC RAM",       "0xE000",	},

		{ "SRAM0",        "0x0000",	},
		{ "SRAM1",        "0x0100",	},
		{ "SRAM2",        "0x0200",	},
		{ "SRAM3",        "0x0300",	},
		{ "SRAM4",        "0x0400",	},
		{ "SRAM5",        "0x0500",	},
		{ "SRAM6",        "0x0600",	},
		{ "SRAM7",        "0x0700",	},
		{ "SRAM8",        "0x0800",	},
		{ "SRAM9",        "0x0900",	},
		{ "SRAMA",        "0x0A00",	},
		{ "SRAMB",        "0x0B00",	},
		{ "SRAMC",        "0x0C00",	},
		{ "SRAMD",        "0x0D00",	},
		{ "SRAME",        "0x0E00",	},
		{ "SRAMF",        "0x0F00",	},

	};


	const struct_main_menu type_F4_menu[]=
	{ 
		{ "SRAM:0X8000",       "(C00)",	},
		{ "SRAM:0X8000",       "(C00)",	},
		{ "SRAM:0X8000",       "(C00)",	},
		{ "SRAM:0X8000",       "(C00)",	},
		{ "SRAM:0X8000",       "(C00)",	},
		{ "SRAM:0X8000",       "(C00)",	},
		{ "SRAM:0X8000",       "(C00)",	},
		{ "SRAM:0X8000",       "(C00)",	},
		{ "SRAM:0X8000",       "(C00)",	},
		{ "SRAM:0X8000",       "(C00)",	},
		{ "SRAM:0X8000",       "(C00)",	},
		{ "SRAM:0X8000",       "(C00)",	},
		{ "SRAM:0X8000",       "(C00)",	},
		{ "SRAM:0X8000",       "(C00)",	},
		{ "SRAM:0X8000",       "(C00)",	},
		{ "SRAM:0X8000",       "(C00)",	},
		{ "SRAM:0X8000",       "(C00)",	},
		{ "SRAM:0X8000",       "(C00)",	},
		{ "SRAM:0X8000",       "(C00)",	},
		{ "SRAM:0X8000",       "(C00)",	},
		{ "SRAM:0X8000",       "(C00)",	},
		{ "SRAM:0X8000",       "(C00)",	},
		{ "SRAM:0X8000",       "(C00)",	},
		{ "SRAM:0X8000",       "(C00)",	},



		{ "SRAM:0X9F00",       "(DF0)",	},


	};


	const struct_main_menu type_F5_menu[]=
	{ 
		{ "UART1",       "0x01",	},
		{ "UART2",       "0x02",	},

		{ "SWUC",        "0x04",	},
		{ "KBC_MS",        "0x05",	},
		{ "KBC_KB",        "0x06",	},
		{ "CIR",        "0x0A",	},
		{ "SMFI",        "0x0F",	},
		{ "BRAM",        "0x10",	},
		{ "PMC1",        "0x11",	},
		{ "PMC2",        "0x12",	},
		{ "SPI",        "0x13",	},
		{ "PECI",        "0x14",	},
		{ "PMC3",        "0x17",	},
		{ "PMC4",        "0x18",	},
		{ "PMC5",        "0x19",	},

	};


	const struct_main_menu type_F6_menu[]=
	{ 
		{ "EXGPIO",       "",	},
		{ "SwitchEC",       "",	},

		{ "Show Spec Reg",        "",	},
		{ "Save All Reg",        "",	},
		{ "Save Current Page",        "",	},
		{ "Save Byte(Max 32)",        "",	},
		{ "Save Page To Page",        "",	},

	};


	for(nline=0;nline<5;nline++)
	{
		mvprintw(0,defnColBgn+nline*10,type_main_menu[nline].menu);
	}

    bool blrunning=true;
    attroff(A_BLINK);
    
    int menu_num=0;
    while(blrunning)
    {
		ch = getch();			/* If raw() hadn't been called
						 * we have to press enter before it
						 * gets to the program 		*/
		if(ch == KEY_F(7))		/* Without keypad enabled this will */
			printw("F7 Key pressed");/*  not get to us either	*/
						/* Without noecho() some ugly escape
						 * charachters might have been printed
						 * on screen			*/

		else if(ch == KEY_F(2))
		{
			menu_num=2;
			keypad(stdscr, FALSE);
    		main_menu(menu_num);
    		keypad(stdscr, TRUE);
			//update_panels();
			//doupdate();
			touchwin(stdscr);
		    refresh();
    		menu_num=0;
		}

		else if(ch == KEY_F(3))
		{
			menu_num=3;
    		main_menu(menu_num);
    		menu_num=0;
		}

	    else if(ch == KEY_F(9))
	    	blrunning=false;
	    else if(ch == KEY_F(8))
	    {
	    	goto_first_cellyx(stdscr,&type_cell_data);	
	    }
		else if( 
			(ch >='0' && ch<='9')||
			(ch >='a' && ch<='f')||
			(ch >='A' && ch<='F')
			)
		{	//printw("The pressed key is ");
			if(ch >='a' && ch<='f')
				ch=ch-32;

			int npos;
			editcellyx(stdscr, ch, &type_cell_data);

		}
		else if( ch==KEY_LEFT || ch==KEY_RIGHT || ch==KEY_UP || ch==KEY_DOWN )
		{
			selectcellyx(stdscr,ch,&type_cell_data);


		}
		else
		{
			//gityx(stdscr,);
			//move(20,0);
		}

		refresh();			/* Print it on to the real screen */
		
	}

    //getch();			/* Wait for user input */
	endwin();			/* End curses mode		  */

	return 0;
}







#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
#define CTRLD 	4

char *choices[] = {
    "Choice 1",
    "Choice 2",
    "Choice 3",
    "Choice 4",
	"Choice 5",
	"Choice 6",
	"Choice 7",
	"Choice 8",
	"Choice 9",
	"Choice 10",
	"Choice 11",
	"Choice 12",
	"Choice 13",
	"Choice 14",
	"Choice 15",
    "Exit",
    (char *)NULL,
};

void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color);

int main_menu(int menu_num)
{	ITEM **my_items;
	int c;				
	MENU *my_menu;
        WINDOW *my_menu_win;
        int n_choices, i;

	ITEM *cur_item;	

	/* Initialize curses */
	//initscr();
	//start_color();
    //    cbreak();
    //    noecho();
	//keypad(stdscr, TRUE);
	init_pair(1, COLOR_RED, COLOR_BLACK);
	init_pair(2, COLOR_CYAN, COLOR_BLACK);

	/* Create items */
        n_choices = ARRAY_SIZE(choices);
        my_items = (ITEM **)calloc(n_choices, sizeof(ITEM *));
        for(i = 0; i < n_choices; ++i)
        {
            //my_items[i] = new_item(choices[i], choices[i]);
            my_items[i] = new_item(choices[i], "");
        }

	/* Crate menu */
	my_menu = new_menu((ITEM **)my_items);

	/* Create the window to be associated with the menu */
        my_menu_win = newwin(16, 20, 2, 4);
        keypad(my_menu_win, TRUE);
     
	/* Set main window and sub window */
        set_menu_win(my_menu, my_menu_win);
        set_menu_sub(my_menu, derwin(my_menu_win, 12, 18, 3, 1));
	set_menu_format(my_menu, 11, 1);
			
	/* Set menu mark to the string " * " */
        set_menu_mark(my_menu, " * ");

	/* Print a border around the main window and print a title */
        box(my_menu_win, 0, 0);
	print_in_middle(my_menu_win, 1, 0, 20, "My Menu", COLOR_PAIR(1));
	mvwaddch(my_menu_win, 2, 0, ACS_LTEE);
	mvwhline(my_menu_win, 2, 1, ACS_HLINE, 18);
	mvwaddch(my_menu_win, 2, 19, ACS_RTEE);
        
	/* Post the menu */
	post_menu(my_menu);
	wrefresh(my_menu_win);
	
	attron(COLOR_PAIR(2));
	mvprintw(LINES - 2, 0, "Use PageUp and PageDown to scoll down or up a page of items");
	mvprintw(LINES - 1, 0, "Arrow Keys to navigate (F1 to Exit)");
	attroff(COLOR_PAIR(2));
	refresh();

	while((c = wgetch(my_menu_win)) != KEY_F(1))
	{       switch(c)
	        {	case KEY_DOWN:
				menu_driver(my_menu, REQ_DOWN_ITEM);
				break;
			case KEY_UP:
				menu_driver(my_menu, REQ_UP_ITEM);
				break;
			case KEY_NPAGE:
				menu_driver(my_menu, REQ_SCR_DPAGE);
				break;
			case KEY_PPAGE:
				menu_driver(my_menu, REQ_SCR_UPAGE);
				break;

			case 10:	/* Enter */
			//case KEY_ENTER:
				cur_item = current_item(my_menu);
				move(LINES - 2, 0);
				clrtoeol();
				mvprintw(LINES - 2, 0, "You have chosen %d item with name %s and description %s", 
				item_index(cur_item) + 1,  item_name(cur_item), 
				item_description(cur_item));
				
				refresh();
				pos_menu_cursor(my_menu);
				break;

		}
                wrefresh(my_menu_win);
	}	

	/* Unpost and free all the memory taken up */
        unpost_menu(my_menu);
        free_menu(my_menu);
        for(i = 0; i < n_choices; ++i)
                free_item(my_items[i]);
	
	if(my_menu_win)
	{
		wborder(my_menu_win, ' ', ' ', ' ',' ',' ',' ',' ',' ');
		wrefresh(my_menu_win);
		delwin(my_menu_win);
	}
	//endwin();

}

void print_in_middle(WINDOW *win, int starty, int startx, int width, char *string, chtype color)
{	int length, x, y;
	float temp;

	if(win == NULL)
		win = stdscr;
	getyx(win, y, x);
	if(startx != 0)
		x = startx;
	if(starty != 0)
		y = starty;
	if(width == 0)
		width = 80;

	length = strlen(string);
	temp = (width - length)/ 2;
	x = startx + (int)temp;
	wattron(win, color);
	mvwprintw(win, y, x, "%s", string);
	wattroff(win, color);
	refresh();
}







